52. location set new & delete

기본 operator new와 기본 operator delete
void* operator new(std::size_t) throw(std::bad_alloc);
//
void operator delete(void* rawMemory) throw();
//
void operator delete(void* rawMemory, std::size_t size) throw();
new로 객체의 크기를 메모리 할당하는 경우,
operator new를 먼저 호출하고, 객체의 생성자를 호출한다.
객체의 생성자가 예외를 던지는 경우를 위해 C++ 런타임 시스템을 new와 매칭되어 있는 delete를 호출한다.

비기본형 operator new(매개변수를 추가로 갖는 operator new)를 선언한 경우,
class Widget{
public:
// ...
// opeartor new
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
// operator delete()
static void operator delete(void* pMemory, size_t size) throw();
}
매개변수를 추가로 갖는 operator new를 위치지정(placement) new라고 한다.
대체로 어떤 객체를 생성시킬 메모리 위치를 나타내는 포인터를 매개변수로 받도록 선언해서 사용한다.
// C++ <new>
void* operator new(std::size_t, void* pMemory) throw();
위와 같이 선언해서 STL vector에서 미사용 공간에 벡터를 추가할 때, 호출해서 사용할 수 있다.

위에서 Widget 을 new로 할당할 때,
Widget* pw=new (std::cerr) Widget;
operator new를 호출하는데 ostream에 cerr를 인자로 전달
Widget 생성자에서 예외가 발생하게 되면,
C++ 런타임 시스템은 호출된 operator new가 받아들이는 매개변수의 개수 및 타입이 똑같은 버전의
operator delete를 호출한다.

따라서 Widget에 아래와 같은 같은 버전의 operator delete를 추가해 주어야 한다.
class Widget{
public:
// ...
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
static void operator delete(void* pMemory) throw();
static void operator delete(void* pMemory, std::ostream& logStream) throw();
// ...
};
위처럼 구현되어 있으면, Widget 생성자가 예외를 던지더라도, 메모리가 누출되지 않는다.
위치 지정 operator delete는 위치 지정 operator new와 함께 호출된 생성자가 예외를 던질 때만 호출된다.
이 후 소멸될 때는 기본형 operator delete가 호출됨
바깥쪽 유효범위에 있는 어떤 함수나 클래스 멤버 함수의 이름이 같은 경우,
바깥쪽 유효범위의 함수가 “이름만 같아도” 가려지게 된다.
(매개변수 타입을 구분하지 않으며, 가상 비가상 상태도 구분하지 않는다.)

동일한 유효범위에서 동일한 이름에 대하여 다른 매개변수를 가질 때, 오버로딩
class Base{
public:
// ...
static void* operator new(std::size_t size, std::ostream& logStream) throw(std::bad_alloc);
// ...
};
class Derived: public Base{
public:
// ...
static void* operator new(std::size_t size) throw(bad_alloc);
// ...
};
Base* pb=new Base; // error, operator new
Base* pb=new (std::cerr) Base; // Base::operator new
Derived* pd=new (std::clog) Derived; // Base::operator new
Derived* pd=new Derived; // Derived::operator new
표준 operator new
// operator new
void* operator new(std::size_t) throw(bad_alloc);
// operator new
void* operator new(std::size_t, void*) throw();
// operator new(LIKE C)
void* operator new(std::size_t, std::nothrow_t&) throw();
new & delete 표준 형태를 모두 포함하는 클래스를 정의
class StandardNewDeleteForms{
public:
// new/delete
static void* operator new(std::size_t size) throw(std::bad_alloc){
return ::operator new(size);
}
static void operator delete(void* pMemory) throw(){
::operator delete(pMemory);
}
// new/delete
static void* operator new(std::size_t size, void* ptr) throw(){
return ::operator new(size, ptr);
}
static void operator delete(void* pMemory, void* ptr) throw(){
return ::operator delete(pMemroy, ptr);
}
// new/delete
static void* operator new(std::size_t size, const std::notrhow_t nt) throw(){
return ::operator new(size, nt);
}
static void operator delete(void* pMemory, const std::nothrow_t&) throw(){
return ::operator delete(pMemroy);
}
};
이 후 사용하고 싶을 때, 위의 클래스를 상속해서 사용한다.
class Widget: public StandardNewDeleteForms{
public:
//
using StandardNewDeleteForms::operator new;
using StandardNewDeleteForms::operator delete;
// new/delete
static void* operator new(std::size_t size, std::osteram& logStream) throw(std::bad_alloc);
static void operator delete(void* pMemory, std::ostream) throw();
// ...
};